home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 2.iso / dist / fw_glimpse.idb / usr / freeware / src / glimpse-3.0 / compress / uncast.c.z / uncast.c
C/C++ Source or Header  |  1997-09-09  |  19KB  |  621 lines

  1. /* Copyright (c) 1994 Burra Gopal, Udi Manber.  All Rights Reserved. */
  2.  
  3. /*
  4.  * uncast.c:    main text uncompression routines. Exports tuncompress() called
  5.  *        from main() in main_uncast.c, and one other simple routine
  6.  *        tuncompressible_file().
  7.  */
  8.  
  9. #include "defs.h"
  10. #include <sys/time.h>
  11. #if defined(__NeXT__)
  12.                                       /* NeXT has no <utime.h> */
  13. struct utimbuf {
  14.         time_t actime;          /* access time */
  15.         time_t modtime;         /* modification time */
  16. };
  17. #else
  18. #include <utime.h>
  19. #endif
  20. #define MYEOF    0xffffffff
  21.  
  22. extern int RESERVED_CHARS;
  23. extern int MAX_WORDS;
  24. extern int SPECIAL_WORDS;
  25. extern int BEGIN_SPECIAL_WORDS;
  26. extern int END_SPECIAL_WORDS;
  27. extern int NUM_SPECIAL_DELIMITERS;
  28. extern int END_SPECIAL_DELIMITERS;
  29. extern int ONE_VERBATIM;
  30. extern int TC_FOUND_BLANK, TC_FOUND_NOTBLANK;
  31. extern char comp_signature[SIGNATURE_LEN];
  32. extern hash_entry freq_words_table[MAX_WORD_LEN+2][256];    /* 256 is the maximum possible number of special words */
  33. extern char freq_words_strings[256][MAX_WORD_LEN+2];
  34. extern int freq_words_lens[256];
  35. extern char *compress_string_table[DEF_MAX_WORDS]; /*[MAX_WORD_LEN+2]; */
  36.  
  37. extern int usemalloc, next_free_strtable;
  38.  
  39. initialize_tuncompress(string_file, freq_file, flags)
  40.     char    *string_file, *freq_file;
  41.     int    flags;
  42. {
  43.     FILE    *stringfp;
  44.  
  45.     if (!initialize_common(freq_file, flags)) return 0;
  46.     next_free_strtable = 0;
  47.     memset(compress_string_table, '\0', sizeof(char *) * DEF_MAX_WORDS);
  48.     if (MAX_WORDS == 0) return 1;
  49.  
  50.     /* Load uncompress dictionary */
  51.     if ((stringfp = fopen(string_file, "r")) == NULL) {
  52.         if (flags & TC_ERRORMSGS) {
  53.             fprintf(stderr, "cannot open cast-dictionary file: %s\n", string_file);
  54.             fprintf(stderr, "(use -H to give a dictionary-dir or run 'buildcast' to make a dictionary)\n");
  55.         }
  56.         return 0;
  57.     }
  58.     if (!build_string(compress_string_table, stringfp, -1, 0)) {    /* read all bytes until end */
  59.         fclose(stringfp);
  60.         return 0;
  61.     }
  62.     fclose(stringfp);
  63.     return 1;
  64. }
  65.  
  66. uninitialize_tuncompress()
  67. {
  68.     int    i;
  69.  
  70.     uninitialize_common();
  71.     if (usemalloc) {
  72.         for (i=0; i<MAX_WORDS; i++) {
  73.             if (compress_string_table[i] != NULL) free(compress_string_table[i]);
  74.         }
  75.     }
  76.     memset(compress_string_table, '\0', sizeof(char *) * DEF_MAX_WORDS);
  77.     next_free_strtable = 0;
  78. }
  79.  
  80. extern int initialize_common_done;
  81.  
  82. /* TRUE if file has the signature in its first 15 bytes, false otherwise */
  83. int
  84. tuncompressible(buffer, num_read)
  85.     char    *buffer;
  86.     int    num_read;
  87. {
  88.     char    *sig = comp_signature;
  89.     int    i;
  90.  
  91.     if (!initialize_common_done) return 0;
  92.     if (num_read < SIGNATURE_LEN - 1) return 0;
  93.     for (i=0; i<SIGNATURE_LEN - 1; i++)
  94.         if (buffer[i] != sig[i]) return 0;
  95.     return 1;
  96.     /* a rewind is not done. hence this is useful even for stdin */
  97. }
  98.  
  99. int
  100. tuncompressible_filename(name, len)
  101.     char    *name;
  102.     int    len;
  103. {
  104.     if (!initialize_common_done) return 0;
  105.     if ((len < strlen(COMP_SUFFIX) + 1) || (strcmp(&name[len-strlen(COMP_SUFFIX)], COMP_SUFFIX))) return 0;
  106.     return 1;
  107. }
  108.  
  109. int
  110. tuncompressible_file(name)
  111.     char    *name;
  112. {
  113.     char    buf[SIGNATURE_LEN + 2];
  114.     int    num;
  115.     FILE    *fp;
  116.  
  117.     if (!initialize_common_done) return 0;
  118.     if (!tuncompressible_filename(name, strlen(name))) return 0;
  119.     if ((fp = fopen(name, "r")) == NULL) return 0;
  120.     num = fread(buf, 1, SIGNATURE_LEN - 1, fp);
  121.     fclose(fp);
  122.     return(tuncompressible(buf, num));
  123. }
  124.  
  125. tuncompressible_fp(fp)
  126.     FILE    *fp;
  127. {
  128.     char    buf[SIGNATURE_LEN + 2];
  129.     int    num;
  130.  
  131.     if (!initialize_common_done) return 0;
  132.     num = fread(buf, 1, SIGNATURE_LEN - 1, fp);
  133.     return(tuncompressible(buf, num));
  134. }
  135.  
  136. /* defined in misc.c */
  137. extern char special_texts[];
  138. extern char special_delimiters[];
  139.  
  140. #define process_special_char(c)\
  141. {\
  142.     if (outfp != NULL) {\
  143.         switch(c)\
  144.         {\
  145.         case TWOBLANKS:\
  146.             if ((maxoutlen >= 0) && (outlen + 2 >= maxoutlen)) return outlen;\
  147.             putc(' ', outfp);\
  148.             outlen ++;\
  149.             putc(' ', outfp);\
  150.             outlen ++;\
  151.             break;\
  152.         case BLANK:\
  153.             if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  154.             putc(' ', outfp);\
  155.             outlen ++;\
  156.             break;\
  157. \
  158.         case TWOTABS:\
  159.             if ((maxoutlen >= 0) && (outlen + 2 >= maxoutlen)) return outlen;\
  160.             putc('\t', outfp);\
  161.             outlen ++;\
  162.             putc('\t', outfp);\
  163.             outlen ++;\
  164.             break;\
  165.         case TAB:\
  166.             if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  167.             putc('\t', outfp);\
  168.             outlen ++;\
  169.             break;\
  170. \
  171.         case TWONEWLINES:\
  172.             if ((maxoutlen >= 0) && (outlen + 2 >= maxoutlen)) return outlen;\
  173.             putc('\n', outfp);\
  174.             outlen ++;\
  175.             putc('\n', outfp);\
  176.             outlen ++;\
  177.             break;\
  178.         case NEWLINE:\
  179.             if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  180.             putc('\n', outfp);\
  181.             outlen ++;\
  182.             break;\
  183. \
  184.         default:\
  185.             if ((c < END_SPECIAL_TEXTS) && (c >= BEGIN_SPECIAL_TEXTS)) {\
  186.                 if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  187.                 putc(special_texts[c - BEGIN_SPECIAL_TEXTS], outfp); outlen ++;\
  188.             }\
  189.             else if ((c < END_SPECIAL_DELIMITERS) && (c >= BEGIN_SPECIAL_DELIMITERS)) {\
  190.                 if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  191.                 putc(special_delimiters[c - BEGIN_SPECIAL_DELIMITERS], outfp); outlen ++;\
  192.             }\
  193.             else if ((c < END_SPECIAL_WORDS) && (c >= BEGIN_SPECIAL_WORDS)) {\
  194.                 if ((maxoutlen >= 0) && (outlen + freq_words_lens[c - BEGIN_SPECIAL_WORDS] >= maxoutlen)) return outlen;\
  195.                 fprintf(outfp, "%s", freq_words_strings[c - BEGIN_SPECIAL_WORDS]); outlen += freq_words_lens[c - BEGIN_SPECIAL_WORDS];\
  196.             }\
  197.             /* else should not have called this function */\
  198.         }\
  199.     }\
  200.     if (outbuf != NULL) {\
  201.         switch(c)\
  202.         {\
  203.         case TWOBLANKS:\
  204.             if ((maxoutlen >= 0) && (outlen + 2 >= maxoutlen)) return outlen;\
  205.             outbuf[outlen ++] = ' ';\
  206.             outbuf[outlen ++] = ' ';\
  207.             break;\
  208.         case BLANK:\
  209.             if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  210.             outbuf[outlen ++] = ' ';\
  211.             break;\
  212. \
  213.         case TWOTABS:\
  214.             if ((maxoutlen >= 0) && (outlen + 2 >= maxoutlen)) return outlen;\
  215.             outbuf[outlen ++] = '\t';\
  216.             outbuf[outlen ++] = '\t';\
  217.             break;\
  218.         case TAB:\
  219.             if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  220.             outbuf[outlen ++] = '\t';\
  221.             break;\
  222. \
  223.         case TWONEWLINES:\
  224.             if ((maxoutlen >= 0) && (outlen + 2 >= maxoutlen)) return outlen;\
  225.             outbuf[outlen ++] = '\n';\
  226.             outbuf[outlen ++] = '\n';\
  227.             break;\
  228.         case NEWLINE:\
  229.             if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  230.             outbuf[outlen ++] = '\n';\
  231.             break;\
  232. \
  233.         default:\
  234.             if ((c < END_SPECIAL_TEXTS) && (c >= BEGIN_SPECIAL_TEXTS)) {\
  235.                 if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  236.                 outbuf[outlen ++] = special_texts[c - BEGIN_SPECIAL_TEXTS];\
  237.             }\
  238.             else if ((c < END_SPECIAL_DELIMITERS) && (c >= BEGIN_SPECIAL_DELIMITERS)) {\
  239.                 if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;\
  240.                 outbuf[outlen ++] = special_delimiters[c - BEGIN_SPECIAL_DELIMITERS];\
  241.             }\
  242.             else if ((c < END_SPECIAL_WORDS) && (c >= BEGIN_SPECIAL_WORDS)) {\
  243.                 /* printf("-->%s\n", freq_words_strings[c-BEGIN_SPECIAL_WORDS]); */\
  244.                 if ((maxoutlen >= 0) && (outlen + freq_words_lens[c - BEGIN_SPECIAL_WORDS] >= maxoutlen)) return outlen;\
  245.                 memcpy(outbuf+outlen, freq_words_strings[c - BEGIN_SPECIAL_WORDS], freq_words_lens[c - BEGIN_SPECIAL_WORDS]);\
  246.                 outlen += freq_words_lens[c - BEGIN_SPECIAL_WORDS]; \
  247.             }\
  248.             /* else should not have called this function */\
  249.         }\
  250.     }\
  251. }
  252.  
  253. int UNCAST_ERRORS = 0;
  254.  
  255. /* Uncompresses input from indata and outputs it into outdata: returns number of chars in output */
  256. int
  257. tuncompress(indata, maxinlen, outdata, maxoutlen, flags)
  258.     void    *indata, *outdata;
  259.     int    maxinlen, maxoutlen;
  260.     int    flags;
  261. {
  262.     unsigned short    index, dindex;
  263.     unsigned int    c;
  264.     int    verbatim_state = 0;
  265.     int    inlen, outlen = 0;
  266.     FILE    *infp = NULL, *outfp = NULL;
  267.     unsigned char    *inbuf = NULL, *outbuf = NULL;
  268.     int    easysearch = flags&TC_EASYSEARCH;
  269.     int    untilnewline = flags&TC_UNTILNEWLINE;
  270.  
  271.     if (flags & TC_SILENT) return 0;
  272.     if (maxinlen < 0) {
  273.         infp = (FILE *)indata;
  274.         if ((easysearch = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;    /* ignore parameter: take from file */
  275.         inlen = SIGNATURE_LEN;
  276.     }
  277.     else {    /* don't care about signature: user's responsibility */
  278.         inbuf = (unsigned char *)indata;
  279.         inlen = 0;
  280.     }
  281.  
  282.     if (maxoutlen < 0) {
  283.         outfp = (FILE *)outdata;
  284.     }
  285.     else {
  286.         outbuf = (unsigned char *)outdata;
  287.     }
  288.  
  289.     if (easysearch) {
  290.         ONE_VERBATIM = EASY_ONE_VERBATIM;
  291.         NUM_SPECIAL_DELIMITERS = EASY_NUM_SPECIAL_DELIMITERS;
  292.         END_SPECIAL_DELIMITERS = EASY_END_SPECIAL_DELIMITERS;
  293.     }
  294.     else {
  295.         ONE_VERBATIM = HARD_ONE_VERBATIM;
  296.         NUM_SPECIAL_DELIMITERS = HARD_NUM_SPECIAL_DELIMITERS;
  297.         END_SPECIAL_DELIMITERS = HARD_END_SPECIAL_DELIMITERS;
  298.     }
  299.  
  300.     if (TC_FOUND_BLANK) {
  301.         if (outfp != NULL) putc(' ', outfp);
  302.         if (outbuf != NULL) outbuf[outlen] = ' ';
  303.         outlen ++;
  304.     }
  305.     TC_FOUND_BLANK = 0;    /* default: use result of previous backward_tcompressed_word only */
  306.  
  307.     /*
  308.      * The algorithm, as expected, is a complete inverse of the compression
  309.      * algorithm: see tcompress.c in this directory to understand this function.
  310.      * I've used gotos since the termination condition is too complex.
  311.      * The two sub-parts are exactly the same except for verbatim processing.
  312.      * Actually, loop-unrolling was done here: you can combine them together but...
  313.      */
  314.     if (easysearch)
  315.     {    /* compress was done in a context-free way to speed up searches */
  316.         while(1) {
  317.             if((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  318.  
  319.         bypass_getc1:
  320.             if (c == ONE_VERBATIM) {
  321.                 if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  322.                 if ((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  323.                 if (outfp != NULL) putc(c, outfp);    /* no processing whatsoever */
  324.                 if (outbuf != NULL) outbuf[outlen] = c;
  325.                 outlen ++;
  326.             }
  327.             else if (verbatim_state) {
  328.                 if (c == END_VERBATIM) verbatim_state = 0;
  329.                 else {
  330.                     if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  331.                     if (outfp != NULL) putc(c, outfp);
  332.                     if (outbuf != NULL) outbuf[outlen] = c;
  333.                     outlen ++;
  334.                 }
  335.             }
  336.             else if (c < END_SPECIAL_CHARS) {
  337.                 process_special_char(c)
  338.                 if ( ((c == NEWLINE) || (c == TWONEWLINES)) && untilnewline)
  339.                     return outlen;
  340.             }
  341.             else if (c == BEGIN_VERBATIM) {
  342.                 if((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  343.                 if ((maxoutlen >= 0) && (outlen + 1>= maxoutlen)) return outlen;
  344.                 if (outfp != NULL) putc(c, outfp);
  345.                 if (outbuf != NULL) outbuf[outlen] = c;
  346.                 outlen ++;
  347.                 verbatim_state = 1;
  348.             }
  349.             else if (c == END_VERBATIM) {    /* not in verbatim state, still end_verbatim! */
  350.                 verbatim_state = 0;
  351.                 fprintf(stderr, "error in decompression after %d chars [verbatim processing]. skipping...\n", inlen);
  352.                 UNCAST_ERRORS = 1;
  353.             }
  354.             else
  355.             {
  356.             above1:
  357.                 if (c < RESERVED_CHARS) {    /* this is a special-word but not a special char */
  358.                     process_special_char(c)
  359.                 }
  360.                 else {    /* it is an index of a word in the dictionary since 1st byte >= RESERVED_CHARS */
  361.                     index = c;
  362.                     index <<= 8;
  363.                     if ((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  364.                     index |= c;
  365.                     dindex = decode_index(index);
  366.                     if(dindex < MAX_WORDS) {
  367.                         if ((maxoutlen >= 0) && (outlen + AVG_WORD_LEN >= maxoutlen)) return outlen;
  368.                         if (outfp != NULL) outlen += myfpcopy(outfp, compress_string_table[dindex]);
  369.                         if (outbuf != NULL) {
  370.                             outlen += mystrcpy(outbuf+outlen, compress_string_table[dindex]);
  371.                         }
  372.                         if ((maxoutlen >= 0) && (outlen >= maxoutlen)) return outlen;
  373.                     }
  374.                     else {
  375.                         fprintf(stderr, "error in decomperssion after %d chars [bad index %x]. skipping...\n", inlen, index);
  376.                         UNCAST_ERRORS = 1;
  377.                     }
  378.                 }
  379.  
  380.             /* process_char_after_word1: */
  381.                 /* now to see what follows the word: a blank or a special delimiter or not-blank */
  382.                 if((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) {
  383.                     if (!TC_FOUND_NOTBLANK) {
  384.                         if (outfp != NULL) putc(' ', outfp);
  385.                         if (outbuf != NULL) outbuf[outlen] = ' ';
  386.                         outlen ++;
  387.                     }
  388.                     TC_FOUND_NOTBLANK = 0;    /* default: use result of previous forward_tcompressed_word only */
  389.                     return outlen;
  390.                 }
  391.                 else if (c < MAX_SPECIAL_CHARS) {
  392.                     if ((c < END_SPECIAL_DELIMITERS) && (c >= BEGIN_SPECIAL_DELIMITERS)) {
  393.                         if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  394.                         if (outfp != NULL) putc(special_delimiters[c - BEGIN_SPECIAL_DELIMITERS], outfp);
  395.                         if (outbuf != NULL) outbuf[outlen] = special_delimiters[c - BEGIN_SPECIAL_DELIMITERS];
  396.                         outlen ++;
  397.                     }
  398.                     else if (c != NOTBLANK) {
  399.                         if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  400.                         if (outfp != NULL) putc(' ', outfp);
  401.                         if (outbuf != NULL) outbuf[outlen] = ' ';
  402.                         outlen ++;
  403.                         goto bypass_getc1;
  404.                     }
  405.                     /* else go normal getc */
  406.                 }
  407.                 else {    /* can be one of the special_words or a dictionary index */
  408.                     if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  409.                     if (outfp != NULL) putc(' ', outfp);
  410.                     if (outbuf != NULL) outbuf[outlen] = ' ';
  411.                     outlen ++;
  412.                     goto above1;
  413.                 }
  414.             }
  415.         }
  416.     }
  417.     else
  418.     {    /* compression was done in a context sensitive fashion w/o regards to search */
  419.         while(1) {
  420.             if((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  421.  
  422.         bypass_getc2:
  423.             if (verbatim_state) {
  424.                 if (c == END_VERBATIM) verbatim_state = 0;
  425.                 else if (c == BEGIN_VERBATIM) goto verbatim_processing;
  426.                 else {
  427.                     if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  428.                     if (outfp != NULL) putc(c, outfp);
  429.                     if (outbuf != NULL) outbuf[outlen] = c;
  430.                     outlen ++;
  431.                 }
  432.             }
  433.             else if (c < END_SPECIAL_CHARS) {
  434.                 process_special_char(c)
  435.                 if ( ((c == NEWLINE) || (c == TWONEWLINES)) && untilnewline)
  436.                 return outlen;
  437.             }
  438.             else if (c == BEGIN_VERBATIM) {
  439.             verbatim_processing:
  440.                 if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  441.                 if((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  442.                 if (outfp != NULL) putc(c, outfp);
  443.                 if (outbuf != NULL) outbuf[outlen] = c;
  444.                 outlen ++;
  445.                 if ((c!=BEGIN_VERBATIM) && (c!=END_VERBATIM)) verbatim_state = 1;    /* only _these_ are escape characters */
  446.             }
  447.             else if (c == END_VERBATIM) {    /* not in verbatim state, still end_verbatim! */
  448.                 verbatim_state = 0;
  449.                 fprintf(stderr, "error in decompression after %d chars [verbatim processing]. skipping...\n", inlen);
  450.                 UNCAST_ERRORS = 1;
  451.             }
  452.             else
  453.             {
  454.             above2:
  455.                 if (c < RESERVED_CHARS) {    /* this is a special-word but not a special char */
  456.                     process_special_char(c)
  457.                 }
  458.                 else {    /* it is an index of a word in the dictionary since 1st byte >= RESERVED_CHARS */
  459.                     index = c;
  460.                     index <<= 8;
  461.                     if ((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) return outlen;
  462.                     index |= c;
  463.                     dindex = decode_index(index);
  464.                     if(dindex < MAX_WORDS) {
  465.                         if ((maxoutlen >= 0) && (outlen + AVG_WORD_LEN >= maxoutlen)) return outlen;
  466.                         if (outfp != NULL) outlen += myfpcopy(outfp, compress_string_table[dindex]);
  467.                         if (outbuf != NULL) {
  468.                             outlen += mystrcpy(outbuf+outlen, compress_string_table[dindex]);
  469.                         }
  470.                         if ((maxoutlen >= 0) && (outlen >= maxoutlen)) return outlen;
  471.                     }
  472.                     else {
  473.                         fprintf(stderr, "error in decomperssion after %d chars [bad index %x]. skipping...\n", inlen, index);
  474.                         UNCAST_ERRORS = 1;
  475.                     }
  476.                 }
  477.  
  478.             /* process_char_after_word2: */
  479.                 /* now to see what follows the word: a blank or a special delimiter or not-blank */
  480.                 if((c = mygetc(infp, inbuf, maxinlen, &inlen)) == MYEOF) {
  481.                     if (!TC_FOUND_NOTBLANK) {
  482.                         if (outfp != NULL) putc(' ', outfp);
  483.                         if (outbuf != NULL) outbuf[outlen] = ' ';
  484.                         outlen ++;
  485.                     }
  486.                     TC_FOUND_NOTBLANK = 0;    /* default: use result of previous forward_tcompressed_word only */
  487.                     return outlen;
  488.                 }
  489.                 else if (c < MAX_SPECIAL_CHARS) {
  490.                     if ((c < END_SPECIAL_DELIMITERS) && (c >= BEGIN_SPECIAL_DELIMITERS)) {
  491.                         if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  492.                         if (outfp != NULL) putc(special_delimiters[c - BEGIN_SPECIAL_DELIMITERS], outfp);
  493.                         if (outbuf != NULL) outbuf[outlen] = special_delimiters[c - BEGIN_SPECIAL_DELIMITERS];
  494.                         outlen ++;
  495.                     }
  496.                     else if (c != NOTBLANK) {
  497.                         if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  498.                         if (outfp != NULL) putc(' ', outfp);
  499.                         if (outbuf != NULL) outbuf[outlen] = ' ';
  500.                         outlen ++;
  501.                         goto bypass_getc2;
  502.                     }
  503.                     /* else go normal getc */
  504.                 }
  505.                 else {    /* can be one of the special_words or a dictionary index */
  506.                     if ((maxoutlen >= 0) && (outlen + 1 >= maxoutlen)) return outlen;
  507.                     if (outfp != NULL) putc(' ', outfp);
  508.                     if (outbuf != NULL) outbuf[outlen] = ' ';
  509.                     outlen ++;
  510.                     goto above2;
  511.                 }
  512.             }
  513.         }
  514.     }
  515. }
  516.  
  517. #define FUNCTION    tuncompress_file
  518. #define DIRECTORY    tuncompress_directory
  519. #include "trecursive.c"
  520.  
  521. /* returns #bytes (>=0) in the uncompressed file, -1 if major error (not able to uncompress) */
  522. int
  523. tuncompress_file(name, outname, flags)
  524.     char    *name;
  525.     char    *outname;
  526.     int    flags;
  527. {
  528.     FILE    *fp;
  529.     FILE    *outfp;
  530.     int    inlen, ret;
  531.     struct stat statbuf;
  532.     /* struct timeval tvp[2]; */
  533.     struct utimbuf tvp;
  534.  
  535.     if (name == NULL) return -1;
  536.     if (-1 == stat(name, &statbuf)) {
  537.         if (flags & TC_ERRORMSGS)
  538.             fprintf(stderr, "permission denied or non-existent: %s\n", name);
  539.         return -1;
  540.     }
  541.     if (S_ISDIR(statbuf.st_mode)) {
  542.         if (flags & TC_RECURSIVE) return tuncompress_directory(name, outname, flags);
  543.         if (flags & TC_ERRORMSGS)
  544.             fprintf(stderr, "skipping directory: %s\n", name);
  545.         return -1;
  546.     }
  547.         if (!S_ISREG(statbuf.st_mode)) {
  548.                 if (flags & TC_ERRORMSGS)
  549.             fprintf(stderr, "not a regular file, skipping: %s\n", name);
  550.                 return -1;
  551.     }
  552.  
  553.     inlen = strlen(name);
  554.     if (!tuncompressible_filename(name, inlen)) {
  555.         if (!(flags & TC_RECURSIVE) && (flags & TC_ERRORMSGS))
  556.             fprintf(stderr, "no %s extension, skipping: %s\n", COMP_SUFFIX, name);
  557.         return -1;
  558.     }
  559.     if ((fp = fopen(name, "r")) == NULL) {
  560.         if (flags & TC_ERRORMSGS)
  561.             fprintf(stderr, "permission denied or non-existent: %s\n", name);
  562.         return -1;
  563.     }
  564.     if (!tuncompressible_fp(fp)) {
  565.         if (flags & TC_ERRORMSGS)
  566.             fprintf(stderr, "signature does not match, skipping: %s\n", name);
  567.         fclose(fp);
  568.         return -1;
  569.     }
  570.     if (flags & TC_SILENT) {
  571.         printf("%s\n", name);
  572.         fclose(fp);
  573.         return 0;
  574.     }
  575.  
  576.     /* Create and open output file */
  577.     strncpy(outname, name, MAX_LINE_LEN);
  578.     outname[inlen - strlen(COMP_SUFFIX)] = '\0';
  579.     if (!access(outname, R_OK)) {
  580.         if (!(flags & TC_OVERWRITE)) {
  581.             fclose(fp);
  582.             return 0;
  583.         }
  584.         else if (!(flags & TC_NOPROMPT)) {
  585.             char    s[8];
  586.             printf("overwrite %s? (y/n): ", outname);
  587.             scanf("%c", s);
  588.             if (s[0] != 'y') {
  589.                 fclose(fp);
  590.                 return 0;
  591.             }
  592.         }
  593.     }
  594.     if ((outfp = fopen(outname, "w")) == NULL) {
  595.         if (flags & TC_ERRORMSGS)
  596.             fprintf(stderr, "cannot open for writing: %s\n", outname);
  597.         fclose(fp);
  598.         return -1;
  599.     }
  600.  
  601.     UNCAST_ERRORS = 0;
  602.     if ( ((ret = tuncompress(fp, -1, outfp, -1, flags)) > 0) && !UNCAST_ERRORS && (flags & TC_REMOVE)) {
  603.         unlink(name);
  604.     }
  605.  
  606.     fclose(fp);
  607.     fflush(outfp);
  608.     fclose(outfp);
  609.     /*
  610.     tvp[0].tv_sec = statbuf.st_atime;
  611.     tvp[0].tv_usec = 0;
  612.     tvp[1].tv_sec = statbuf.st_mtime;
  613.     tvp[1].tv_usec = 0;
  614.     utimes(outname, tvp);
  615.     */
  616.     tvp.actime = statbuf.st_atime;
  617.     tvp.modtime = statbuf.st_mtime;
  618.     utime(outname, &tvp);
  619.     return ret;
  620. }
  621.